//public class ClassObject{
//    public static void main(String[] args){
//        System.out.println("Class & Object");
//    }
//
//
//    /**
//     * 类和对象 引用
//     *      如果一个变量的类型是 类类型，而非基本类型，那么该变量又叫做引用。
//     */
//    void Cite(){
//        /**
//         * 引用和指向
//         */
//        //创建一个对象， 但是也仅仅是创建了一个对象，没有办法访问它
//        new Heros();
//
//        //使用一个引用来指向这个对象
//        Heros h = new Heros(); // h这个变量是Hero类型，又叫做引用， “=”的意思指的是h这个引用代表右侧创建的对象， “代表”在面向对象里，又叫做“指向”
//
//
//        /**
//         * 多个引用，一个对象
//         */
//        //使用一个引用来指向这个对象
//        Heros h1 = new Heros();
//        Heros h2 = h1;  //h2指向h1所指向的对象
//        Heros h3 = h1;
//        Heros h4 = h1;
//        Heros h5 = h4;
//        //h1,h2,h3,h4,h5 五个引用，都指向同一个对象
//
//
//        /**
//         * 一个引用，多个对象
//         */
//        // 一个引用，同一时间，只能指向一个对象
//        Heros garen =  new Heros();
//        garen =  new Heros();
//    }
//
//
//    /**
//     * 类和对象 继承
//     */
//    void Inherit(){
//        /**
//         * 物品类 Item
//         */
//        class Item {
//            String name;
//            int price;
//        }
//
//        /**
//         * 武器类 Weapon（不继承）
//         */
//        class Weapon{
//            // 独立设计 name 和 price 属性
//            // 同时多了一个属性 damage 攻击力
//            String name;
//            int price;
//            int damage; //攻击力
//        }
//
//        /**
//         * 武器类 Weapon（继承类Item）
//         */
//        class Weapon extends Item{
//            int damage; //攻击力
//
//            void main(String[] args) {
//                Weapon infinityEdge = new Weapon();
//                infinityEdge.damage = 65; //damage属性在类Weapon中新设计的
//
//                infinityEdge.name = "无尽之刃";//name属性，是从Item中继承来的，就不需要重复设计了
//                infinityEdge.price = 3600;
//            }
//        }
//    }
//
//
//    /**
//     * 类和对象 方法重载
//     *      方法的重载指的是方法名一样，但是参数类型不一样
//     */
//    void HeavyLoad(){
//        class ADHero extends Heros {
//            /**
//             * attack方法的重载
//             */
//            // 方法名是一样的，但是参数类型不一样
//            // 在调用方法attack的时候，会根据传递的参数类型以及数量，自动调用对应的方法
//            public void attack() {
//                System.out.println(name + " 进行了一次攻击 ，但是不确定打中谁了");
//            }
//            public void attack(Heros h1) {
//                System.out.println(name + "对" + h1.name + "进行了一次攻击 ");
//            }
//            public void attack(Heros h1, Heros h2) {
//                System.out.println(name + "同时对" + h1.name + "和" + h2.name + "进行了攻击 ");
//            }
//
//            /**
//             * 可变数量的参数  ※
//             */
//            // 此 attack 方法， 即可代表上述所有的 attack 重载方法了
//            public void attack(Heros... heros) {
//                for (int i = 0; i < heros.length; i++) {
//                    System.out.println(name + " 攻击了 " + heros[i].name);
//                }
//            }
//
//            void main(String[] args) {
//                ADHero bh = new ADHero();
//                bh.name = "赏金猎人";
//
//                Heros h1 = new Heros();
//                h1.name = "盖伦";
//                Heros h2 = new Heros();
//                h2.name = "提莫";
//
//                bh.attack(h1);
//                bh.attack(h1, h2);
//            }
//        }
//    }
//
//
//    /**
//     * 类和对象 构造方法
//     *      通过一个类创建一个对象，这个过程叫做实例化
//     *      实例化是通过调用构造方法(又叫做构造器)实现的
//     */
//    void Constructor(){
//        class Hero {
//            String name;
//            float hp;
//            float armor;
//            int moveSpeed;
//
//            /**
//             * 什么是构造方法
//             */
//            // 方法名和类名一样（包括大小写）
//            // 没有返回类型
//            public Hero() {
//                System.out.println("实例化一个对象的时候，必然调用构造方法");
//            }
//
//            /**
//             * 隐式的构造方法
//             */
//            //这个无参的构造方法，如果不写，
//            //就会默认提供一个无参的构造方法
//            //  public Hero(){
//            //      System.out.println("调用Hero的构造方法");
//            //  }
//
//
//            /**
//             * 如果提供了一个有参的构造方法
//             */
//            // 一旦提供了一个有参的构造方法
//            // 同时又没有显式的提供一个无参的构造方法
//            // 那么默认的无参的构造方法，就“木有了“
//            public Hero(String heroname){
//                name = heroname;
//            }
//            Hero garen =  new Hero("盖伦");
//            Hero teemo =  new Hero(); //无参的构造方法“木有了”
//
//
//            void main(String[] args) {
//                //实例化一个对象的时候，必然调用构造方法
//                Hero h = new Hero();
//            }
//        }
//
//        class Hero1 {
//            String name;
//            float hp;
//            float armor;
//            int moveSpeed;
//
//            /**
//             * 构造方法的重载
//             */
//            //带一个参数的构造方法
//            public Hero1(String heroname){
//                name = heroname;
//            }
//            //带两个参数的构造方法
//            public Hero1(String heroname, float herohp){
//                name = heroname;
//                hp = herohp;
//            }
//
//            void main(String[] args) {
//                Hero1 garen =  new Hero1("盖伦");
//                Hero1 teemo =  new Hero1("提莫",383);
//            }
//        }
//    }
//
//
//    /**
//     * 类和对象 this
//     */
//    void This(){
//        class Hero {
//            String name; //姓名
//            float hp; //血量
//            float armor; //护甲
//            int moveSpeed; //移动速度
//
//            /**
//             * this代表当前对象
//             */
//            //打印内存中的虚拟地址
//            public void showAddressInMemory(){
//                System.out.println("打印this看到的虚拟地址："+this);
//            }
//
//            /**
//             * 通过this访问属性
//             */
//            //参数名和属性名一样
//            //在方法体中，只能访问到参数name
//            public void setName1(String name){
//                name = name;
//            }
//            //为了避免setName1中的问题
//            public void setName3(String name){
//                //name代表的是参数name
//                //this.name代表的是属性name
//                this.name = name;
//            }
//
//            /**
//             * 通过this调用其他的构造方法
//             */
//            //带一个参数的构造方法
//            public Hero(String name){
//                System.out.println("一个参数的构造方法");
//                this.name = name;
//            }
//            //带两个参数的构造方法
//            public Hero(String name,float hp){
//                this(name); // 如果要在一个构造方法中，调用另一个构造方法，可以使用this()
//                System.out.println("两个参数的构造方法");
//                this.hp = hp;
//            }
//
//
//            void main(String[] args) {
//                Hero garen =  new Hero();
//                garen.name = "盖伦";
//                //直接打印对象，会显示该对象在内存中的虚拟地址
//                //格式：Hero@c17164 c17164即虚拟地址，每次执行，得到的地址不一定一样
//                System.out.println("打印对象看到的虚拟地址："+garen);
//                garen.showAddressInMemory(); //调用showAddressInMemory，打印该对象的this，显示相同的虚拟地址
//
//                Hero h = new Hero("提莫",383);
//                h.setName3("garen");
//                System.out.println(h.name);
//            }
//
//        }
//    }
//
//
//    /**
//     * 类和对象 传参
//     *      变量有两种类型 基本类型 和 类类型
//     *      参数也是变量，所以传参也分为 基本类型传参、类类型传参
//     */
//    void PassingReferences(){
//        class Hero {
//            String name; //姓名
//            float hp; //血量
//            float armor; //护甲
//            int moveSpeed; //移动速度
//
//            public Hero(){}
//
//            public Hero(String name,float hp){
//                this.name = name;
//                this.hp = hp;
//            }
//
//            /**
//             * 基本类型传参
//             */
//            //回血
//            public void huixue(int xp){
//                hp = hp + xp;
//                //回血完毕后，血瓶=0
//                xp=0;
//            }
//
//            /**
//             * 引用 与 =
//             */
//            // 如果一个变量是基本类型
//            //      比如 int hp = 50;
//            //      我们就直接管hp叫变量
//            //      =表示赋值的意思。
//            // 如果一个变量是类类型
//            //      比如 Hero h = new Hero();
//            //      我们就管h叫做引用。
//            //      =不再是赋值的意思
//            //      =表示指向的意思
//            // 比如 Hero h = new Hero();
//            // 这句话的意思是
//            // 引用h，指向一个Hero对象
//
//
//            /**
//             * 类类型传参 ： 类类型又叫引用
//             */
//            // 攻击一个英雄，并让他掉damage点血
//            public void attack(Hero hero, int damage) {
//                hero.hp = hero.hp - damage;
//            }
//
//
//            void main(String[] args) {
//                Hero teemo =  new Hero("提莫",383);
//                //血瓶，其值是100
//                int xueping = 100;
//                //提莫通过这个血瓶回血
//                teemo.huixue(xueping); // 基本类型传参
//                System.out.println(xueping);
//
//
//                Hero garen = new Hero("盖伦", 616);
//                garen.attack(teemo, 100); // 类类型传参
//                System.out.println(teemo.hp);
//            }
//        }
//    }
//
//
//    /**
//     * 类和对象 包
//     */
//    void Pack(){
//        // Hero,ADHero 规划在一个包，叫做charactor（角色）
//        // Item,Weapon规划在另一个包下，叫做 property(道具)
//
//        /**
//         * 把比较接近的类，规划在同一个包下
//         */
//        package charactor; //在最开始的地方声明该类所处于的包名
//
//        /**
//         * 使用其他包下的类，必须 import
//         */
//        //Weapon类在其他包里，使用必须进行import
//        import property.Weapon;
//
//        class Hero {
//            String name; //姓名
//            float hp; //血量
//            float armor; //护甲
//            int moveSpeed; //移动速度
//
//            //装备一把武器
//            public void equip(Weapon w){ }
//        }
//    }
//
//
//    /**
//     * 类和对象 访问修饰符
//     *      成员变量有四种修饰符
//     *          private 私有的
//     *          protected 受保护的
//     *          public 公共的
//     *          package/friendly/default 不写
//     */
//    void AccessModifiers(){
//        /**
//         * 类之间的关系
//         *      以Hero为例:
//         *          自身：指的是Hero自己
//         *          同包子类：ADHero 这个类是Hero的子类，并且和Hero处于同一个包下
//         *          不同包子类：Support 这个类是Hero的子类，但是在另一个包下
//         *          同包类： GiantDragon 这个类和Hero是同一个包，但是彼此没有继承关系
//         *          其他类：Item 这个类，在不同包，也没有继承关系的类
//         */
//        // | - src
//        // |    - charactor
//        // |        - ADHero.java
//        // |        - GiantDragon.java
//        // |        - Hero.java
//        // |    - charactor1
//        // |        - Support.java
//        // |    - property
//        // |        - Item.java
//        // |        - Weapon.java
//
//
//        class Hero {
//            /**
//             * private 私有的
//             *      使用private修饰属性：
//             *          自身： 是可以访问的
//             *          同包子类：  不能继承
//             *          不同包子类： 不能继承
//             *          同包类：    不能访问
//             *          其他包类：  不能访问
//             */
//            //属性id是private的，只有Hero自己可以访问
//            //子类不能继承
//            //其他类也不能访问
//            private int id;
//
//            /**
//             * package/friendly/default 不写，即没有修饰符
//             *      自身： 是可以访问的
//             *      同包子类：  可继承
//             *      不同包子类： 不能继承
//             *      同包类：    可访问
//             *      其他包类：  不能访问
//             */
//            // 无修饰符的属性 hp
//            // 自己可以访问
//            // 同包子类可以继承
//            // 不同包子类不能继承
//            // 同包类可以访问
//            // 其它包类不能访问
//            float hp;
//
//            /**
//             * protected 受保护的
//             *      自身： 是可以访问的
//             *      同包子类：  可继承
//             *      不同包子类： 可继承
//             *      同包类：    可访问
//             *      其他包类：  不能访问
//             */
//            // protected饰符的属性 moveSpeed
//            // 自己可以访问
//            // 同包子类可以继承
//            // 不同包子类可以继承
//            // 同包类可以访问
//            // 其它包类不能访问
//            protected int moveSpeed;
//
//            /**
//             * public 公共的
//             *      自身： 是可以访问的
//             *      同包子类：  可继承
//             *      不同包子类： 可继承
//             *      同包类：    可访问
//             *      其他包类：  可访问
//             */
//            // public的属性 name
//            // 自己可以访问
//            // 同包子类可以继承
//            // 不同包子类可以继承
//            // 同包类可以访问
//            // 其它包类可以访问
//            public String name;
//
//
//            /**
//             * 那么什么情况该用什么修饰符呢？
//             */
//            // 1. 属性通常使用private封装起来
//            // 2. 方法一般使用public用于被调用
//            // 3. 会被子类继承的方法，通常使用protected
//            // 4. package用的不多，一般新手会用package,因为还不知道有修饰符这个东西
//            // 再就是作用范围最小原则
//            // 简单说，能用private就用private，不行就放大一级，用package,再不行就用protected，最后用public。 这样就能把数据尽量的封装起来，没有必要露出来的，就不用露出来了
//        }
//    }
//
//
//    /**
//     * 类和对象 类属性
//     */
//    void ClassAttributes(){
//        /**
//         * 类属性:
//         *      当一个属性被static修饰的时候，就叫做类属性，又叫做静态属性
//         *      当一个属性被声明成类属性，那么所有的对象，都共享一个值
//         */
//        class Hero {
//            public String name; //实例属性，对象属性，非静态属性
//            protected float hp;
//            static String copyright; //类属性,静态属性
//            public static void main(String[] args) {
//                Hero garen =  new Hero();
//                garen.name = "盖伦";
//                Hero.copyright = "版权由Riot Games公司所有";
//                System.out.println(garen.name);
//                System.out.println(garen.copyright);
//            }
//        }
//
//        /**
//         * 访问类属性
//         */
//        // 访问类属性有两种方式
//        // 1. 对象.类属性    garen.copyright
//        // 2. 类.类属性     Hero.copyright
//        // 这两种方式都可以访问类属性，访问即修改和获取，但是建议使用第二种 类.类属性 的方式进行，这样更符合语义上的理解
//
//        /**
//         * 什么时候使用对象属性?  什么时候使用类属性?
//         */
//        // 如果一个属性，每个英雄都不一样，比如name，这样的属性就应该设计为对象属性，因为它是跟着对象走的，每个对象的name都是不同的
//        // 如果一个属性，所有的英雄都共享，都是一样的，那么就应该设计为类属性。比如血量上限，所有的英雄的血量上限都是 9999，不会因为英雄不同，而取不同的值。 这样的属性，就适合设计为类属性
//    }
//
//
//    /**
//     * 类和对象 类方法
//     */
//    void ClassMethods(){
//        /**
//         * 类方法： 又叫做静态方法
//         * 对象方法： 又叫实例方法，非静态方法
//         *
//         * 访问一个对象方法，必须建立在有一个对象的前提的基础上
//         * 访问类方法，不需要对象的存在，直接就访问
//         */
//        class Hero {
//            public String name;
//            protected float hp;
//            //实例方法,对象方法，非静态方法
//            //必须有对象才能够调用
//            public void die(){
//                hp = 0;
//            }
//            //类方法，静态方法
//            //通过类就可以直接调用
//            public static void battleWin(){
//                System.out.println("battle win");
//            }
//            public static void main(String[] args) {
//                Hero garen =  new Hero();
//                garen.name = "盖伦";
//                //必须有一个对象才能调用
//                garen.die();
//
//                //无需对象，直接通过类调用
//                Hero.battleWin();
//            }
//        }
//
//
//        /**
//         * 调用类方法
//         */
//        // 调用类方法也有两种方式
//        // 1. 对象.类方法    garen.battleWin();
//        // 2. 类.类方法     Hero.battleWin();
//        // 这两种方式都可以调用类方法，但是建议使用第二种 类.类方法 的方式进行，这样更符合语义上的理解。
//        // 并且在很多时候，并没有实例，比如在前面练习的时候用到的随机数的获取办法 Math.random() , random()就是一个类方法，直接通过类Math进行调用，并没有一个Math的实例存在。
//
//
//        /**
//         * 什么时候设计对象方法?  什么时候设计类方法?
//         */
//        // 如果在某一个方法里，调用了对象属性，比如
//        public String getName(){
//            return name;
//        }
//        // name属性是对象属性，只有存在一个具体对象的时候，name才有意义。 如果方法里访问了对象属性，那么这个方法，就必须设计为对象方法
//
//        // 如果一个方法，没有调用任何对象属性，那么就可以考虑设计为类方法，比如
//        public static void printGameDuration(){
//            System.out.println("已经玩了10分50秒");
//        }
//        // printGameDuration 打印当前玩了多长时间了，不和某一个具体的英雄关联起来，所有的英雄都是一样的。 这样的方法，更带有功能性色彩
//        // 就像取随机数一样，random()是一个功能用途的方法 Math.random()
//    }
//
//
//    /**
//     * 类和对象 属性初始化
//     */
//    void InitOfAttributes(){
//        /**
//         * 对象属性初始化
//         *      1. 声明该属性的时候初始化
//         *      2. 构造方法中初始化
//         *      3. 初始化块
//         */
//        public String name = "some hero"; //声明该属性的时候初始化
//        protected float hp;
//        public Hero(){
//            hp = 100; //构造方法中初始化
//        }
//        {
//            maxHP = 200; //初始化块
//        }
//
//        /**
//         * 类属性初始化
//         *      1. 声明该属性的时候初始化
//         *      2. 静态初始化块
//         */
//        float maxHP;
//        public static int itemCapacity=8; //声明的时候 初始化
//        static{
//            itemCapacity = 6; //静态初始化块 初始化
//        }
//    }
//
//
//    /**
//     * 类和对象 单例模式
//     *      又叫做 Singleton模式，指的是一个类，在一个JVM里，只有一个实例存在。
//     */
//    void SingletonPattern(){
//        /**
//         * 饿汉式单例模式
//         */
//        class GiantDragon1 {
//            //私有化构造方法使得该类无法在外部通过new 进行实例化
//            private GiantDragon1(){ }
//            //准备一个类属性，指向一个实例化对象。 因为是类属性，所以只有一个
//            private static GiantDragon1 instance = new GiantDragon1();
//
//            //public static 方法，提供给调用者获取上面定义的对象
//            public static GiantDragon1 getInstance(){
//                return instance;
//            }
//        }
//
//
//        /**
//         * 懒汉式单例模式
//         */
//        class GiantDragon2 {
//            //私有化构造方法使得该类无法在外部通过new 进行实例化
//            private GiantDragon2(){ }
//            //准备一个类属性，用于指向一个实例化对象，但是暂时指向null
//            private static GiantDragon2 instance;
//
//            //public static 方法，返回实例对象
//            public static GiantDragon2 getInstance(){
//                //第一次访问的时候，发现instance没有指向任何对象，这时实例化一个对象
//                if(null==instance){
//                    instance = new GiantDragon2();
//                }
//                //返回 instance指向的对象
//                return instance;
//            }
//        }
//
//        /**
//         * 什么时候使用饿汉式? 什么时候使用懒汉式?
//         */
//        // 饿汉式： 是立即加载的方式，无论是否会用到这个对象，都会加载。
//        // 如果在构造方法里写了性能消耗较大，占时较久的代码，比如建立与数据库的连接，那么就会在启动的时候感觉稍微有些卡顿。
//        //
//        // 懒汉式： 是延迟加载的方式，只有使用的时候才会加载。 并且有线程安全的考量(鉴于同学们学习的进度，暂时不对线程的章节做展开)。
//        // 使用懒汉式，在启动的时候，会感觉到比饿汉式略快，因为并没有做对象的实例化。 但是在第一次调用的时候，会进行实例化操作，感觉上就略慢。
//        //
//        // 看业务需求，如果业务上允许有比较充分的启动和初始化时间，就使用饿汉式，否则就使用懒汉式
//
//        /**
//         * 单例模式三元素
//         */
//        // 即 什么是单例模式？
//        // 回答的时候，要答到三元素
//        //      1. 构造方法私有化
//        //      2. 静态属性指向实例
//        //      3. public static的 getInstance方法，返回第二步的静态属性
//    }
//
//
//    /**
//     * 类和对象 枚举类型
//     */
//    void EnumerationType(){
//        /**
//         * 预先定义的常量
//         */
//        // 枚举enum是一种特殊的类(还是类)，使用枚举可以很方便的定义常量
//        // 比如设计一个枚举类型 季节，里面有4种常量
//        public enum Season {
//            SPRING, SUMMER, AUTUMN, WINTER
//        }
//        // 一个常用的场合就是switch语句中，使用枚举来进行判断
//        // 注：因为是常量，所以一般都是全大写
//        void main1() {
//            Season season = Season.SPRING;
//            switch (season) {
//                case SPRING:
//                    System.out.println("春天");
//                    break;
//                case SUMMER:
//                    System.out.println("夏天");
//                    break;
//                case AUTUMN:
//                    System.out.println("秋天");
//                    break;
//                case WINTER:
//                    System.out.println("冬天");
//                    break;
//            }
//        }
//
//
//        /**
//         * 使用枚举的好处
//         */
//        // 假设在使用switch的时候，不是使用枚举，而是使用int，而int的取值范围就不只是1-4，有可能取一个超出1-4之间的值，这样判断结果就似是而非了。（因为只有4个季节）
//        // 但是使用枚举，就能把范围死死的限定在这四个当中， 而不会出现范围之外的内容
//
//
//        /**
//         * 遍历枚举
//         */
//        // 借助增强型for循环，可以很方便的遍历一个枚举都有哪些常量
//        for (Season s : Season.values()) {
//            System.out.println(s);
//        }
//    }
//
//}
